﻿using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Common.Cache
{
    /// <summary>
    /// Redis 服务
    /// </summary>
    public class RedisCacheService : IRedisCacheService
    {
        private readonly bool isGetRedis;

        public RedisCacheService(IConfiguration configuration)
        { 
            var redisConn = configuration["RedisConn"];
            this.isGetRedis = !string.IsNullOrEmpty(redisConn);
            if (!isGetRedis)
            {
                return;
            }

            var redisConns = redisConn.Split(",");
            if (redisConns.Length == 1)
            { 
                var csredis = new CSRedis.CSRedisClient(redisConn);
                RedisHelper.Initialization(csredis);
            }
            else
            {
                var redisConnArray = redisConns.Select(t => $"{t},defaultDatabase=0,poolsize=100,writeBuffer=10240").ToArray();
                var csredis = new CSRedis.CSRedisClient(null, redisConnArray);
                RedisHelper.Initialization(csredis);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string Get(string key)
        {
            if (!this.isGetRedis)
            {
                return null;
            }

            return RedisHelper.Get(GetMd5Key(key));
        }

        public T Get<T>(string key)
        {
            if (!this.isGetRedis)
            {
                return default(T);
            }

            return RedisHelper.Get<T>(GetMd5Key(key));
        }

        public async Task<string> GetAsync(string key)
        {
            if (!this.isGetRedis)
            {
                return null;
            }

            return await RedisHelper.GetAsync(GetMd5Key(key));
        }

        public async Task<T> GetAsync<T>(string key)
        {
            if (!this.isGetRedis)
            {
                return default(T);
            }

            return await RedisHelper.GetAsync<T>(GetMd5Key(key));
        }

        public void Set(string key, object obj, TimeSpan? expire)
        {
            if (!this.isGetRedis)
            {
                return;
            }

            if (expire == null)
            {
                expire = new TimeSpan(30, 0, 0, 0);
            }

            RedisHelper.Set(GetMd5Key(key), obj, expire.Value);
        }

        public async Task SetAsync(string key, object obj, TimeSpan? expire)
        {
            if (!this.isGetRedis)
            {
                return;
            }

            if (expire == null)
            {
                expire = new TimeSpan(30, 0, 0, 0);
            }

            await RedisHelper.SetAsync(GetMd5Key(key), obj, expire.Value);
        }

        public void Del(params string[] keys)
        {
            if (!this.isGetRedis)
            {
                return;
            }

            if (keys != null)
            {
                _ = RedisHelper.Del(keys.Select(t => GetMd5Key(t)).ToArray());
            }
        }

        public async Task DelAsync(params string[] keys)
        {
            if (!this.isGetRedis)
            {
                return; 
            }

            if (keys != null)
            {
                _ = await RedisHelper.DelAsync(keys.Select(t => GetMd5Key(t)).ToArray());
            }
        }

        public bool Exists(string key)
        {
            if (!this.isGetRedis)
            {
                return false;
            }

            return RedisHelper.Exists(GetMd5Key(key));
        }

        public async Task<bool> ExistsAsync(string key)
        {
            if (!this.isGetRedis)
            {
                return false;
            }

            return await RedisHelper.ExistsAsync(GetMd5Key(key));
        }

        public void HashSet(string key, string field, string value)
        {
            if (!this.isGetRedis)
            {
                return;
            }

            _ = RedisHelper.HSet(GetMd5Key(key), field, value);
        }

        public string HashGet(string key, string field)
        {
            if (!this.isGetRedis)
            {
                return null;
            }

            return RedisHelper.HGet(GetMd5Key(key), field);
        }

        public void HashDel(string key, string field)
        {
            if (!this.isGetRedis)
            {
                return;
            }

            _ = RedisHelper.HDel(GetMd5Key(key), field);
        }

        public bool Expire(string key, TimeSpan expire)
        {
            if (!this.isGetRedis)
            {
                return true;
            }

            return RedisHelper.Expire(GetMd5Key(key), expire);
        }

        public Dictionary<string, string> HashGetAll(string key)
        {
            if (!this.isGetRedis)
            {
                return new Dictionary<string, string>();
            }

            return RedisHelper.HGetAll(GetMd5Key(key));
        }

        private string GetMd5Key(string key)
        {
            return key.Length < 32 ? key : Hash_MD5_32(key);
        }

        private string Hash_MD5_32(string word, bool toUpper = true)
        {
            var md5csp = System.Security.Cryptography.MD5.Create();
            try
            {
                byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(word);
                byte[] bytHash = md5csp.ComputeHash(bytValue);
                md5csp.Clear();

                ////根据计算得到的Hash码翻译为MD5码
                string hashStr = string.Empty;
                for (int counter = 0; counter < bytHash.Length; counter++)
                {
                    long i = bytHash[counter] / 16;
                    string tempStr;
                    if (i > 9)
                    {
                        tempStr = ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr = ((char)(i + 0x30)).ToString();
                    }

                    i = bytHash[counter] % 16;
                    if (i > 9)
                    {
                        tempStr += ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr += ((char)(i + 0x30)).ToString();
                    }

                    hashStr += tempStr;
                }

                ////根据大小写规则决定返回的字符串
                return toUpper ? hashStr : hashStr.ToLower();
            }
            finally
            {
                md5csp.Dispose();
            }
        }
    }
}
